package com.itheima.model.search.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.nacos.common.utils.MapUtils;
import com.heima.model.common.dtos.PageResponseResult;
import com.heima.model.common.dtos.ResponseResult;
import com.heima.model.common.enums.AppHttpCodeEnum;
import com.heima.model.searchDto.UserSearchDto;
import com.itheima.model.search.service.ArticleSearchService;
import org.apache.commons.lang3.StringUtils;
import org.apache.lucene.search.TotalHits;
import org.apache.lucene.util.QueryBuilder;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.text.Text;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.io.IOException;
import java.lang.reflect.Array;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Service
public class ArticleSearchServiceimpl implements ArticleSearchService {

    @Resource
    private RestHighLevelClient client;
    //实现es的搜索 并进行高亮处理
    @Override
    public ResponseResult search(UserSearchDto dto) throws IOException {
            if (dto==null||StringUtils.isEmpty(dto.getSearchWords())) {
                return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_REQUIRE);
            }

            //准备请求
        SearchRequest request=new SearchRequest("app_article_info");
        //封装DSL语句
        //条件过滤
        BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();//聚合桶
        boolQuery.must(QueryBuilders.multiMatchQuery(dto.getSearchWords(),"title","content"));
        boolQuery.filter(QueryBuilders.rangeQuery("publishTime").lt(dto.getMinBehotTime()));

        request.source().query(boolQuery);
        //规则排序
        request.source().sort("publishTime", SortOrder.DESC);
        //高亮处理
        HighlightBuilder highter = new HighlightBuilder();
        highter.field("title");
        highter.preTags("<font style='color:red; font-size: inherit;'>");
        highter.postTags("</font>");
        //分页条件
        request.source().highlighter(highter);
        request.source().size(10);
        //发送请求
        SearchResponse response = client.search(request, RequestOptions.DEFAULT);
        //获取到响应结果 hits //解析高亮
        SearchHits hits = response.getHits();
        //获取条数
        Long totalHits = hits.getTotalHits().value;
        //获取内容数据
        SearchHit[] hits1 = hits.getHits();
        //将数组里面的内容进行遍历 获取高亮内容并替换数
        List<Map> collect = Arrays.stream(hits1).map(searchHit -> {
            //获取文档数据
            String sourceAsString = searchHit.getSourceAsString();
            //将文档JSON数据转化为Map集合
            Map map = JSON.parseObject(sourceAsString, Map.class);

            //获取出来高亮数据
            Map<String, HighlightField> highlightFields = searchHit.getHighlightFields();
            //判断是否为空
            if (!CollectionUtils.isEmpty(highlightFields)) {
                //获取高亮标头
                HighlightField title = highlightFields.get("title");
                if (title != null) {
                    Text fragment = title.getFragments()[0];
                    //将高亮标题替换原文本
                    map.put("h_title", fragment.toString());
                }
            } else {
                map.put("h_title", map.get("title"));
            }
            return map;
        }).collect(Collectors.toList());

        ResponseResult result = new PageResponseResult(dto.getPageNum(),dto.getPageSize(),totalHits.intValue());
        result.setData(collect);
        return result;
    }
}
